#!/usr/bin/python
# coding:utf-8
"""
封装基本request类
"""
__author__ = 'Martin Wang <357951@qq.com>'

import json
import hashlib
import requests
import urllib
import urllib3
import dataUtils
from urllib import parse
from robot.api import logger
import jwt

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)


class CommonRequestLib:

    def __init__(self):
        """基类初始化
        """
        self.log = logger
        # app端登录参数
        self.app_base_url = None
        self.headers = {
            "Content-Type": "application/json;charset=utf-8",
            "x-microservice-name": "api-gateway"
        }
        self.app_headers = {
            "Content-Type": "application/json;charset=utf-8"
        }
        self.token = None
        self.username = None
        self.password = None

        # web端登录参数
        self.web_base_url = ""
        self.web_token = None
        self.web_username = None
        self.web_password = None
        self.web_headers = {
            "Content-Type": "application/json"
        }

    def login(self, username, password, envInfo):
        """C端登录
        - :param username: 【必填】用户名，类型：string
        - :param password: 【必填】用户登录密码，类型：string
        - :param envInfo: 【必填】环境信息，类型：dict
        - :return: 无返回体
        """
        self.username = username
        self.password = password

        self.app_base_url = envInfo["baseUrlApi"] + "/" + envInfo["capiUrl"]

        self.log.info("Begin to get new token!")
        response = self._get_token(username=username, password=password)
        return response

    def logout(self):
        """清理当前的token
        """
        self.log.info("Start remove headers x-access-token")
        self.app_headers.pop("x-access-token")
        self.log.info("Remove headers' x-access-token OK")

    def _get_token(self, username, password):
        """获取用户token

        - :param username: 【必填】用户登录名，类型：string
        - :param password: 【必填】用户密码，类型：string
        - :return: 无返回体
        """

        self.username = username
        self.password = password
        # 1.准备headers
        headers = self.app_headers

        # 2.组装URL
        uri = "/v1/user/login"
        api_url = self.app_base_url + uri
        # 3.封装请求体
        post_data = {
            "account": self.username,
            "password": self.password,
            "loginTypeEnum": "ACCOUNT_PASSWORD",
            "loginChannelEnum": "APP"
        }
        post_data = json.dumps(post_data)

        # 下发操作
        try:
            self.log.info("Getting token, headers is: {}".format(headers))
            self.log.info("Getting token, url is: {}".format(api_url))
            self.log.info("Getting token, postdata is: {}".format(post_data))

            response = requests.post(url=api_url, data=post_data, headers=headers, verify=False)
            self.log.info("Getting token, the status_code is :{}".format(response.status_code))
            self.log.info("Getting token, the response is :{}".format(response.text))
            assert response.status_code == 200
            content = json.loads(response.text)
            # token_type = content['data']['tokenInfo']['tokenType']
            access_token = content['data']['accessToken']
            # self.token = token_type + " " + access_token
            self.token = access_token
            self.log.info("Token is: {}".format(self.token))
            # 把token加入headers
            self.app_headers['x-access-token'] = self.token
            # 返回用户信息
            response_dict = dict()
            response_dict["code"] = response.status_code
            response_dict["body"] = content
            return response_dict
        except Exception as e:
            raise Exception("Get token failed: {}, login api has no response!".format(e))

    def get_request(self, url, params=None, headers=None, **kwargs):
        """封装get操作
        - : App Get使用
        - :param url: 【必填】请求url, 类型：string
        - :param params: 【可选】查询参数，类型：字典
        - :param headers: 【可选】请求头参数，类型：字典
        - :param kwargs: 【可选】其他必要的参数
        - :return: 返回状态码与响应体
        """
        if params:
            url += "?" + urllib.parse.urlencode(params, '\\')
            url = url.replace('+', "%20")

        if headers:
            for k,v in headers.items():
                self.app_headers[k] = v

        self.log.info("In Get, last url is: {}".format(url))
        self.log.info("In Get, last headers is: {}".format(self.app_headers))
        # 执行请求
        try:
            response = requests.get(url=url, headers=self.app_headers, verify=False, **kwargs)
            content = json.loads(response.text)
        except Exception as e:
            raise Exception("Exception: {}".format(e))

        # 返回状态码与响应体
        response_dict = dict()
        response_dict["code"] = response.status_code
        response_dict["response_time"] = response.elapsed.total_seconds()
        response_dict["body"] = content
        return response_dict

    def post_request(self, url, data, headers=None, params=None, **kwargs):
        """封装post操作
        - : App Post使用
        - :param url: 【必填】请求url, 类型：string
        - :param data: 【必填】请求体, 类型：dict
        - :param headers: 【可选】请求头参数，类型：字典
        - :param kwargs: 【可选】其他必要的参数
        - :return: 返回状态码与响应体
        """
        if headers:
            for k,v in headers.items():
                self.app_headers[k] = v

        if params:
            url += "?" + urllib.parse.urlencode(params, '\\')
            url = url.replace('+', "%20")

        self.log.info("In Post, last url is: {}".format(url))
        self.log.info("In Post, last url is: {}".format(url))
        self.log.info("In Post, last headers is: {}".format(self.app_headers))
        self.log.info("In Post, last postdata is: {}".format(data))
        # 转换请求体，执行请求
        data = json.dumps(data, ensure_ascii=False).encode('utf-8').decode("latin1")  # 解决一些中文编码问题
        try:
            response = requests.post(url=url, data=data, headers=self.app_headers, verify=False, **kwargs)
            content = json.loads(response.text)
        except Exception as e:
            raise Exception("Exception: {}".format(e))

        # 返回状态码与响应体
        response_dict = dict()
        response_dict["code"] = response.status_code
        response_dict["response_time"] = response.elapsed.total_seconds()
        response_dict["body"] = content
        return response_dict

    def post_request_multipart(self, url, file_path, data=None, params=None, **kwargs):
        """提交Multipart/form-data 格式的Post请求
        - : App Post使用
        - :param url: 【必填】url, 类型：string
        - :param file_path:  【必填】文件路径, 类型：string
        - :param data:  【可选】其他请求体, 类型：dict
        - :param kwargs: 【可选】其他必要参数
        - :return: 返回状态码与响应体
        """
        if params:
            url += "?" + urllib.parse.urlencode(params, '\\')
            url = url.replace('+', "%20")
        self.log.info("In Post, last url is: {}".format(url))
        # 转换请求体，执行请求
        try:
            if type(file_path) == list:
                files = []
                for f in file_path:
                    ff = ('files', open(f, 'rb'))
                    files.append(ff)
            elif type(file_path) == str:
                files = {'file': open(file_path, 'rb')}  # 这里提交的python文件对象(字节)
            else:
                files = []
                for k, v in file_path.items():
                    ff = (k, open(v, 'rb'))
                    files.append(ff)
            del self.app_headers["Content-Type"]  # header里不能加content-type
            self.log.info("multipart's post header is：{}".format(self.app_headers))
            self.log.info("multipart's postdata is：{}".format(data))
            self.log.info("multipart's filepath is：{}".format(file_path))
            if data is None:
                response = requests.post(url=url, files=files, headers=self.app_headers, verify=False, **kwargs)
            else:
                response = requests.post(url=url, data=data, files=files, headers=self.app_headers, verify=False,
                                         **kwargs)
            content = json.loads(response.text)
            # 返回状态码与响应体
        except Exception as e:
            raise Exception("Exception: {}".format(e))
        finally:
            self.app_headers["Content-Type"] = "application/json"

        # 返回状态码与响应体
        response_dict = dict()
        response_dict["code"] = response.status_code
        response_dict["response_time"] = response.elapsed.total_seconds()
        response_dict["body"] = content
        return response_dict

    def put_request(self, url, data, **kwargs):
        """封装put操作
        - : App Put使用
        - :param url: 【必填】url, 类型：string
        - :param data: 【必填】请求体, 类型：dict
        - :param kwargs: 【可选】其他必要的参数
        - :return: 返回状态码与响应体
        """
        self.log.info("In Put,last url is: {}".format(url))
        self.log.info("In Put, last headers is: {}".format(self.app_headers))
        self.log.info("In Put, last postdata is: {}".format(data))
        # 转换请求体，执行请求
        try:
            data = json.dumps(data, ensure_ascii=False).encode('utf-8').decode("latin1")
            response = requests.put(url=url, data=data, headers=self.app_headers, verify=False, **kwargs)
            content = json.loads(response.text)
        except Exception as e:
            raise Exception("Exception: {}".format(e))
        # 返回状态码与响应体
        response_dict = dict()
        response_dict["code"] = response.status_code
        response_dict["response_time"] = response.elapsed.total_seconds()
        response_dict["body"] = content
        return response_dict

    def change_user(self, username, password):
        """切换用户

        - :param username: 【必填】用户名, 类型：string
        - :param password: 【必填】密码, 类型：string
        - :return: 无返回体
        """
        self._get_token(username=username, password=password)

    def to_json(self, text):
        """转换成Json格式

        - :param text: 【必填】转换对象, 类型：string
        - :return: Json
        """
        content = json.loads(text)
        return content

    # ##################################################################
    # ##################################################################
    def web_login(self, username, password, env_info):
        """web端登录
        - :param username: 【必填】用户名，类型：string
        - :param password: 【必填】用户登录密码，类型：string
        - :param env_info: 【必填】环境配置信息，类型：dict
        - :return: 无返回体
        """
        self.web_base_url = env_info["baseUrlApi"] + "/" + env_info["bapiUrl"]
        self.web_username = username
        self.web_password = password
        self._web_get_token(username=username, password=password)

    def _web_get_token(self, username, password):
        """web端获取token
        - :param username: 【必填】用户登录名，类型：string
        - :param password: 【必填】用户密码，类型：string
        - :return: 无返回体
        """
        self.web_username = username
        # self.web_password = hashlib.md5(password.encode()).hexdigest()  # 密码md5加密
        self.web_password = password

        # 1.准备headers
        headers = self.web_headers
        # 2.组装URL
        uri = "v1/user/login"
        api_url = self.web_base_url + "/" + uri
        # 3.封装请求体
        post_data = {
            "code": self.web_username,
            "password": self.web_password
        }
        post_data = json.dumps(post_data)

        # 下发操作
        try:
            self.log.info("Getting web token, headers is: {}".format(headers))
            self.log.info("Getting web token, url is: {}".format(api_url))
            self.log.info("Getting web token, postdata is: {}".format(post_data))
            response = requests.post(url=api_url, data=post_data, headers=headers)
            self.log.info("Getting web token, the status_code is :{}".format(response.status_code))
            assert response.status_code == 200
            self.log.info("Getting token, the response is :{}".format(response.text))
            content = json.loads(response.text)
            self.web_token = content['data']['token']
            self.log.info("Web token is: {}".format(self.web_token))
            # 把token加入headers
            self.web_headers['Authorization'] = self.web_token
        except Exception as e:
            raise Exception("Get web token failed: {}".format(e))

    def get_request_web(self, url, params=None, **kwargs):
        """封装web端get操作

        - :param url: 【必填】url, 类型：string
        - :param params: 【可选】查询参数，类型：字典
        - :param kwargs: 【可选】其他必要的参数
        - :return: 返回状态码与响应体
        """
        # 组合params
        if params:
            url += "?" + urllib.parse.urlencode(params)
        self.log.info("In Get, last url is: {}".format(url))
        self.log.info("In Get, last headers is: {}".format(self.web_headers))
        # 执行请求
        try:
            response = requests.get(url=url, headers=self.web_headers, verify=False, **kwargs)
            content = json.loads(response.text)
        except Exception as e:
            raise Exception("Exception: {}".format(e))

        # 返回状态码与响应体
        response_dict = dict()
        response_dict["code"] = response.status_code
        response_dict["response_time"] = response.elapsed.total_seconds()
        response_dict["body"] = content
        return response_dict

    def get_request_web_excel(self, url, filepath, params=None, **kwargs):
        """封装web端get操作,导出excel表格

        - :param url: 【必填】url, 类型：string
        - :param filepath: 【必填】导出的文件存放路径, 类型：string， 比如： E:\test.xls
        - :param kwargs: 【可选】其他必要的参数
        - :return: 成功返回“success”
        """
        # 组合params
        if params:
            url += "?" + urllib.parse.urlencode(params)
        self.log.info("In Get, last url is: {}".format(url))
        self.log.info("In Get, last headers is: {}".format(self.web_headers))
        # 执行请求
        try:
            response = requests.get(url=url, headers=self.web_headers, verify=False, **kwargs)
            fp = open(filepath, "wb")
            fp.write(response.content)
            fp.close()
            return "success"
        except Exception as e:
            raise Exception("Exception: {}".format(e))

    def get_request_web_no_data(self, url, params=None, **kwargs):
        """封装web端get操作

        - :param url: 【必填】url, 类型：string
        - :param params: 【可选】查询参数，类型：字典
        - :param kwargs: 【可选】其他必要的参数
        - :return: 返回状态码与响应体
        """
        # 组合params
        if params:
            url += "?" + urllib.parse.urlencode(params)
        self.log.info("In Get, last url is: {}".format(url))
        self.log.info("In Get, last headers is: {}".format(self.web_headers))
        # 执行请求
        try:
            response = requests.get(url=url, headers=self.web_headers, verify=False, **kwargs)
        except Exception as e:
            raise Exception("Exception: {}".format(e))

        # 返回状态码与响应体
        response_dict = dict()
        response_dict["code"] = response.status_code
        return response_dict

    def post_request_web(self, url, data, **kwargs):
        """封装post操作

        - :param url: 【必填】url, 类型：string
        - :param data: 【必填】请求体, 类型：dict
        - :param kwargs: 【可选】其他必要的参数
        - :return: 返回状态码与响应体
        """
        self.log.info("In Post, last url is: {}".format(url))
        self.log.info("In Post, last headers is: {}".format(self.web_headers))
        self.log.info("In Post, last postdata is: {}".format(data))
        # 转换请求体，执行请求
        # data = json.dumps(data)
        data = json.dumps(data, ensure_ascii=False).encode('utf-8').decode("latin1")  # 解决一些中文编码问题
        try:
            response = requests.post(url=url, data=data, headers=self.web_headers, verify=False, **kwargs)
            content = json.loads(response.text)
        except Exception as e:
            raise Exception("Exception: {}".format(e))

        # 返回状态码与响应体
        response_dict = dict()
        response_dict["code"] = response.status_code
        response_dict["response_time"] = response.elapsed.total_seconds()
        response_dict["body"] = content
        return response_dict

    def post_request_web_excel(self, url, filepath, data, **kwargs):
        """封装web端post操作,导出excel表格

        - :param url: 【必填】url, 类型：string
        - :param filepath: 【必填】导出的文件存放路径, 类型：string， 比如： E:\test.xls
        - :param data: 【必填】请求体, 类型：dict
        - :param kwargs: 【可选】其他必要的参数
        - :return: 成功返回“success”
        """

        self.log.info("In Post, last url is: {}".format(url))
        self.log.info("In Post, last headers is: {}".format(self.web_headers))
        self.log.info("In Post, last postdata is: {}".format(data))
        # 转换请求体，执行请求
        # data = json.dumps(data)
        data = json.dumps(data, ensure_ascii=False).encode('utf-8').decode("latin1")  # 解决一些中文编码问题
        # 执行请求
        try:
            response = requests.post(url=url, data=data, headers=self.web_headers, verify=False, **kwargs)
            # content = json.loads(response.text)
            fp = open(filepath, "wb")
            fp.write(response.content)
            fp.close()
            return "success"
        except Exception as e:
            raise Exception("Exception: {}".format(e))

    def post_request_multipart_web(self, url, file_path=None, data=None, **kwargs):
        """提交Multipart/form-data 格式的Post请求
        - :param url: 【必填】url, 类型：string
        - :param data: 【必填】请求体data, 类型：dict
        - :param file_path:  文【必填】件路径
        - :param kwargs: 【可选】其他必要参数
        - :return: 返回状态码与响应体
        """
        self.log.info("In Post, last url is: {}".format(url))
        # 转换请求体，执行请求
        try:
            files = {'files': open(file_path, 'rb')}  # 这里提交的python文件对象(字节)
            del self.web_headers["Content-Type"]
            self.log.info("multipart's post header is：{}".format(self.web_headers))
            self.log.info("multipart's postdata is：{}".format(data))
            self.log.info("multipart's filepath is：{}".format(file_path))
            if data is None:
                response = requests.post(url=url, files=files, headers=self.web_headers, verify=False, **kwargs)
            else:
                response = requests.post(url=url, data=data, files=files, headers=self.web_headers, verify=False,
                                         **kwargs)
            content = json.loads(response.text)
            # 返回状态码与响应体
        except Exception as e:
            raise Exception("Exception: {}".format(e))
        finally:
            self.web_headers["Content-Type"] = "application/json"

        # 返回状态码与响应体
        response_dict = dict()
        response_dict["code"] = response.status_code
        response_dict["response_time"] = response.elapsed.total_seconds()
        response_dict["body"] = content
        return response_dict

    def put_request_web(self, url, data, **kwargs):
        """封装put操作

        - :param url: 【必填】url, 类型：string
        - :param data: 【必填】请求体, 类型：dict
        - :param kwargs: 【可选】其他必要的参数
        - :return: 返回状态码与响应体
        """
        self.log.info("In Put,last url is: {}".format(url))
        self.log.info("In Put, last headers is: {}".format(self.web_headers))
        self.log.info("In Put, last postdata is: {}".format(data))
        # 转换请求体，执行请求
        try:
            # data = json.dumps(data)
            data = json.dumps(data, ensure_ascii=False).encode('utf-8').decode("latin1")
            response = requests.put(url=url, data=data, headers=self.web_headers, verify=False, **kwargs)
            content = json.loads(response.text)
        except Exception as e:
            raise Exception("Exception: {}".format(e))
        # 返回状态码与响应体
        response_dict = dict()
        response_dict["code"] = response.status_code
        response_dict["response_time"] = response.elapsed.total_seconds()
        response_dict["body"] = content
        return response_dict

    def delete_request_web(self, url, params, **kwargs):
        """封装delete操作

        - :param url: 【必填】url, 类型：string
        - :param params: 【可选】查询参数，类型：字典
        - :param kwargs: 【可选】其他必要的参数
        - :return: 返回状态码与响应体
        """
        # 组合params
        if params:
            url += "?" + urllib.parse.urlencode(params)
        self.log.info("In Delete, last url is: {}".format(url))
        self.log.info("In Delete, last headers is: {}".format(self.web_headers))
        # 发送请求

        try:
            response = requests.delete(url=url, headers=self.web_headers, verify=False, **kwargs)
            content = json.loads(response.text)
        except Exception as e:
            raise Exception("Exception: {}".format(e))
        # 返回状态码与响应体
        response_dict = dict()
        response_dict["code"] = response.status_code
        response_dict["response_time"] = response.elapsed.total_seconds()
        response_dict["body"] = content
        return response_dict

    def download(self, type, url):
        try:
            if type == "xlsx":
                r = requests.get(url)
                path = "XXX\\XXXXX\\test.xlsx"
                with open(path, "wb") as f:
                    f.write(r.content)
                f.close()
            elif type == "word":
                r = requests.get(url)
                path = "test.word"
                with open(path, "wb") as f:
                    f.write(r.content)
                f.close()
            elif type == "jpg":
                r = requests.get(url)
                path = "test.jpg"
                with open(path, "wb") as f:
                    f.write(r.content)
                f.close()
        except  Exception   as  e:
            raise Exception("Exception: {}".format(e))
